//////////////////////////////////////////////////////////////////////////
// $Id: MOS.cpp,v 1.1 2009/04/03 12:46:10 sunjun Exp $
//////////////////////////////////////////////////////////////////////////

#include "Local.h"

//////////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////////

NAMESPACE_BEGIN

//////////////////////////////////////////////////////////////////////////

	MOS::MOS()
	{
		GUARD(MOS::MOS);
		

		UNGUARD;
	}

	MOS::~MOS()
	{
		GUARD(MOS::~MOS);

		// release the virtual machine
		mCfns.clear();
		mObjects.clear();
		mFunctions.clear();		

		// free all of the plugins
		for( std::map< Str, HANDLE >::iterator it = mPlugins.begin(); it != mPlugins.end(); ++it ) 
		{
			MAssert(VA("The plugin(%s) isn`t free.",it->first.c_str()));
		}
		mPlugins.clear();

		UNGUARD;
	}

	/*
	====================
	describe

	describe a internal class for the muse os
	====================
	*/
	INLINE VOID MOS::describe( const CHAR* name, MCFN cfn, const MDISP_MAP * disps )
	{
		GUARD(MOS::describe);

		// if the class has been described?
		std::map<Str,MCFN>::iterator it = mCfns.find(name);
		if( it != mCfns.end() )
		{
			MAssert(VA("Error : the class(%s) has been described.", name));
			return;
		}
		mCfns.insert( std::map<Str,MCFN>::value_type(name, cfn) );

		UNGUARD;
	}

	/*
	====================
	describe

	describe a internal object for the muse os
	====================
	*/	
	INLINE VOID MOS::describe( const CHAR* name, const MObject* obj )
	{
		GUARD(MOS::describe);

		// if the object has been described?
		std::map<Str, MObjectPtr>::iterator it = mObjects.find(name);
		if( it != mObjects.end() )
		{
			MAssert(VA("Error : the object(%s) has been described.", name));
			return;
		}
		mObjects.insert( std::map<Str, MObjectPtr>::value_type(name, (MObject*)obj) );

		UNGUARD;
	}

	/*
	====================
	describe

	describe a internal function for the muse os
	====================
	*/	
	INLINE VOID MOS::describe( const CHAR* name, U32 func, U32 param )
	{
		GUARD(MOS::describe);

		// if the function has been described?
		std::map< Str, std::pair<U32,U32> >::iterator it = mFunctions.find(name);
		if( it != mFunctions.end() )
		{
			MAssert(VA("Error : the function(%s) has been described.", name));
			return;
		}
		mFunctions.insert( std::map< Str, std::pair<U32,U32> >::value_type(name, std::pair<U32,U32>(func,param)) );

		UNGUARD;
	}

	/*
	====================
	create

	create a new object from the muse os
	====================
	*/
	INLINE MObject* MOS::create( const CHAR * class_name ) const
	{
		GUARD(MOS::create);

		// find the create function of the class
		std::map<Str,MCFN>::const_iterator it = mCfns.find(class_name);
		if( it == mCfns.end() )
		{
			MAssert(VA("Error : can`t find the class(%s).", class_name));
			return NULL;
		}
		return it->second();

		UNGUARD;
	}
	
	/*
	====================
	query

	query a object from the muse os
	====================
	*/
	INLINE MObject* MOS::query( const CHAR * object_name ) const
	{
		GUARD(MOS::query);

		// find the object from the object map
		std::map<Str, MObjectPtr>::const_iterator it = mObjects.find(object_name);
		if( it == mObjects.end() )
		{
			MAssert(VA("Error : can`t find the object(%s).", object_name));
			return NULL;
		}
		return it->second.ptr();

		UNGUARD;
	}
	
	/*
	====================
	call

	call a function in the muse os
	====================
	*/
	INLINE BOOL MOS::call( const CHAR* name, MVar* params, U32 count ) const
	{
		GUARD(MOS::call);		

		// find the function from the function map
		std::map< Str, std::pair<U32,U32> >::const_iterator it = mFunctions.find(name);
		if( it != mFunctions.end() )
		{
			// call it
			VOID* func = (VOID*)it->second.first;
			VOID (*paramfn)(VOID* func, MVar *params) = (VOID (*)(VOID* func, MVar *params))it->second.second;
			
			// call the function
			paramfn( func, &params[0] );

			return TRUE;
		}

		return TRUE;

		UNGUARD;
	}
	
	/*
	====================
	execute

	execute a file to the muse os
	====================
	*/
	INLINE BOOL MOS::execute( const CHAR* name ) const
	{
		GUARD(MOS::execute);
	
		return TRUE;

		UNGUARD;
	}	

	/*
	====================
	loadPlugin

	load a plugin to the muse os
	====================
	*/
	INLINE BOOL MOS::loadPlugin( const CHAR* name )
	{
		GUARD(MOS::loadPlugin);		

		Str plugin_name = name;		
		plugin_name += ".dll";

		HANDLE handle = (HANDLE)::LoadLibrary( plugin_name.c_str() );
		if( !handle )
		{
			MAssert( VA("Could not load the plugin : %s", name) );
			return FALSE;
		}
		mPlugins.insert( std::map< Str, HANDLE >::value_type(name, handle) );

		// call the initializePlugin function
		BOOL (CDECL *initializePlugin)() = ( BOOL (CDECL *)() )::GetProcAddress( (HMODULE)handle, "initializePlugin" );
		if( initializePlugin == NULL ) 
		{
			MPrint(VA("Fail to find the function(initializePlugin) from the plugin : %s.",name));
			return FALSE;
		}
		return initializePlugin();

		UNGUARD;
	}

	/*
	====================
	freePlugin

	free a plugin of the muse os
	====================
	*/
	INLINE VOID MOS::freePlugin( const CHAR* name )
	{
		GUARD(MOS::freePlugin);		
		
		// find the plugin from the plugin map
		std::map< Str, HANDLE >::iterator it = mPlugins.find(name);
		if( it == mPlugins.end() ) return;

		// get the uninitializePlugin function and call it
		VOID (CDECL *uninitializePlugin)() = ( VOID (CDECL *)() )::GetProcAddress( (HMODULE)it->second, "uninitializePlugin" );
		if( uninitializePlugin == NULL ) 
		{
			MAssert(VA("Fail to find the function(uninitializePlugin) from the plugin : %s.",it->first.c_str()));
			return;
		}
		uninitializePlugin();

		// free it
		if( !::FreeLibrary( (HMODULE)it->second ) )
		{
			MAssert( VA("Could not free the plugin : %s", it->first.c_str()) );
			return;
		}

		// erase it from the plugin map
		mPlugins.erase(it);

		UNGUARD;
	}

	/*
	====================
	send

	send a event to the muse os
	====================
	*/ 
	INLINE VOID MOS::send()
	{
		GUARD(MOS::send);		

		UNGUARD;
	}

	//////////////////////////////////////////////////////////////////////////	

	/*
	====================
	instance
	====================
	*/ 
	INLINE MOS& CDECL MOS::instance()
	{
		GUARD(MOS::instance);

		static MOS s_os;
		return s_os;

		UNGUARD;
	}

	//////////////////////////////////////////////////////////////////////////
	
	/*
	====================
	MLoadPlugin

		load a plugin to the muse os
	====================
	*/
	INLINE static BOOL CDECL MLoadPlugin( const CHAR* name )
	{
		GUARD(MLoadPlugin);

		return MOS::instance().loadPlugin( name );

		UNGUARD;
	}

	/*
	====================
	MFreePlugin

	free a plugin from the muse os
	====================
	*/
	INLINE static VOID CDECL MFreePlugin( const CHAR* name )
	{
		GUARD(MFreePlugin);

		MOS::instance().freePlugin( name );

		UNGUARD;
	}

	//////////////////////////////////////////////////////////////////////////

	class MArgument
	{	
	public:		
		// constructor
		MArgument( I32* argc, CHAR** argv )
		{
			mArgc = argc;
			mArgv = argv;
		}
		
		// destructor
		virtual ~MArgument()
		{

		}
		
		// read the value from the argument
		INLINE BOOL read(const Str& str)
		{
			I32 pos=find(str);
			if (pos<0) return FALSE;
			return TRUE;
		}
		
		INLINE BOOL read(const Str& str, Str& value1)
		{
			I32 pos=find(str);
			if (pos<0) return FALSE;
			return read(pos,str,value1);
		}
		
		INLINE BOOL read(const Str& str, Str& value1, Str& value2)
		{
			I32 pos=find(str);
			if (pos<0) return FALSE;
			return read(pos,str,value1, value2);
		}
		
		INLINE BOOL read(const Str& str, Str& value1, Str& value2, Str& value3)
		{
			I32 pos=find(str);
			if (pos<0) return FALSE;
			return read(pos,str,value1, value2, value3);
		}
		
		INLINE BOOL read(const Str& str, Str& value1, Str& value2, Str& value3, Str& value4)
		{
			I32 pos=find(str);
			if (pos<0) return FALSE;
			return read(pos,str,value1, value2, value3, value4);
		}
		
	private:
		INLINE BOOL read(I32 pos, const Str& str)
		{
			if (match(pos,str))
			{
				return TRUE;
			}
			return FALSE;
		}
		
		INLINE BOOL read(I32 pos, const Str& str, Str& value1)
		{
			if (match(pos,str))
			{
				if ((pos+1)<*mArgc)
				{
					value1 = mArgv[pos+1];
					return TRUE;
				}
				else
					return FALSE;
			}
			return FALSE;
		}
		
		INLINE BOOL read(I32 pos, const Str& str, Str& value1, Str& value2)
		{
			if (match(pos,str))
			{
				if ((pos+2)<*mArgc)
				{
					value1 = mArgv[pos+1];
					value2 = mArgv[pos+2];
					return TRUE;
				}
				else 
					return FALSE;
			}
			return FALSE;
		}
		
		INLINE BOOL read(I32 pos, const Str& str, Str& value1, Str& value2, Str& value3)
		{
			if (match(pos,str))
			{
				if ((pos+3)<*mArgc)
				{
					value1 = mArgv[pos+1];
					value2 = mArgv[pos+2];
					value3 = mArgv[pos+3];
					return TRUE;
				}
				else
					return FALSE;
			}
			return FALSE;
		}
		
		INLINE BOOL read(I32 pos, const Str& str, Str& value1, Str& value2, Str& value3, Str& value4)
		{
			if (match(pos,str))
			{
				if ((pos+4)<*mArgc)
				{
					value1 = mArgv[pos+1];
					value2 = mArgv[pos+2];
					value3 = mArgv[pos+3];
					value4 = mArgv[pos+4];
					return TRUE;
				}
				else
					return FALSE;
			}
			return FALSE;
		}		
		
		INLINE I32 find(const Str& str) const
		{
			for(I32 pos=0;pos<*mArgc;pos++)
			{
				if (str==mArgv[pos])
				{
					return pos;
				}
			}
			return -1;
		}
		
		INLINE BOOL match(I32 pos, const Str& str) const
		{
			return pos<*mArgc && str==mArgv[pos] ? TRUE : FALSE;
		}

	private:
		I32* mArgc; CHAR**mArgv;
	};

//////////////////////////////////////////////////////////////////////////
	
NAMESPACE_END
		
//////////////////////////////////////////////////////////////////////////
